﻿using NHibernate;
using System.Data;

namespace DataLayer.UoW
{
    public class UnitOfWorkImplementor : IUnitOfWork
    {
        private readonly IUnitOfWorkFactory factory;
        private readonly ISession session;

        public UnitOfWorkImplementor(IUnitOfWorkFactory factory, ISession session)
        {
            this.factory = factory;
            this.session = session;
        }

        #region IDisposable Members

        public void Dispose()
        {
            factory.DisposeUnitOfWork(this);
            session.Dispose();
        }

        public IGenericTransaction BeginTransaction()
        {
            return new GenericTransaction(session.BeginTransaction());
        }

        public IGenericTransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            return new GenericTransaction(session.BeginTransaction(isolationLevel));
        }

        /// <summary>
        /// 
        /// </summary>
        public void TransactionalFlush()
        {
            TransactionalFlush(IsolationLevel.ReadCommitted);
        }

        /// <summary>
        /// Flushes the contents of the NHibernate session.
        /// Important: In the case of an exception during TransactionalFlush do not try to reuse 
        /// the current unit of work since the session is in an inconsistent state and must be 
        /// closed. Thus abandon this UoW and start a new one.
        /// </summary>
        /// <param name="isolationLevel"></param>
        public void TransactionalFlush(IsolationLevel isolationLevel)
        {
            IGenericTransaction tx = BeginTransaction(isolationLevel);
            try
            {
                //forces a flush of the current unit of work.
                tx.Commit();
            }
            catch (ADOException ae)
            {
                log4net.LogManager.GetLogger(GetType()).Error("Error on transaction commit", ae);
                tx.Rollback();
                throw;
            }
            finally
            {
                tx.Dispose();
            }
        }

        #endregion

        /// <summary>
        /// Returns the active state of the internal transaction.
        /// </summary>
        public bool IsInActiveTransaction
        {
            get
            {
                return session.Transaction.IsActive;
            }
        }

        /// <summary>
        /// Returns the factory object.
        /// </summary>
        public IUnitOfWorkFactory Factory
        {
            get
            {
                return factory;
            }
        }

        /// <summary>
        /// Returns the session object.
        /// </summary>
        public ISession Session
        {
            get
            {
                return session;
            }
        }
        
        /// <summary>
        /// Flushes the internal session object.
        /// </summary>
        public void Flush()
        {
            session.Flush();
        }

    }
}
